/*#########################################################################
# Boolbool Server by Saggi Mizrahi.                                       #
#                                                                         #
#   This program is free software; you can redistribute it and/or modify  #
#   it under the terms of the GNU General Public License as published by  #
#   the Free Software Foundation; either version 2 of the License, or     #
#   (at your option) any later version.                                   #
#                                                                         #
#   This program is distributed in the hope that it will be useful,       #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#   GNU General Public License for more details.                          #
#                                                                         #
#   You should have received a copy of the GNU General Public License     #
#   along with this program; if not, write to the                         #
#   Free Software Foundation, Inc.,                                       #
#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         #
##########################################################################*/

Importer.loadQtBinding("qt.core");
Importer.loadQtBinding("qt.network");

Importer.include("common.js");

eStatusCode = {
  200: "OK",
  207: "Multi-Status",
  301: "Moved permanently",
  302: "Found",
  303: "See Other",
  401: "Unauthorized",
  403: "Forbidden",
  404: "Not Found",
  500: "Internal Server Error"
};

function Response(server)
{
  this.code = 200;
  this.content = "";
  this.headers = {"Content-Type" : "text/html"};
}

Response.prototype.toString = function()
{
  return "Response " + this.code + " " + eStatusCode[this.code];
};

function HTTPServer(bindAddr, port)
{
  this._bindAddr = bindAddr;
  this._port = port;
  this._server = new QTcpServer();
  this._server.newConnection.connect(this, this.onConnect);
  this.serverAdress = bindAddr + ":" + port;
  this.serverName = "Boolbool";
  this.serverVersion = "1.0";
  this.routes = [];
}

HTTPServer.prototype.stop = function()
{
  this._server.close();
};

HTTPServer.prototype.toString = function()
{
  return "[Boolbool Server]";
};

HTTPServer.prototype.listen = function()
{
  this._server.listen(this._bindAddr, this._port);
};

HTTPServer.prototype.onConnect = function()
{
  try
  {
    client = this._server.nextPendingConnection();
    client.waitForReadyRead(30000);
    req = this._parseRequest(client);
    
    debug("Request for " + req.path);
    
    var response = new Response();
    
    foundRoute = false;
    try
    { 
      for (i in this.routes)
      {
	routePath = this.routes[i][0];
	routeFunc = this.routes[i][1];
	if (req.path.toString().match(routePath))
	{
	  routeFunc(this, req, response);
	  foundRoute = true;
	  break;
	}
      }
      if (!foundRoute)
      {
	throw 404;
      }
    }
    catch(errCode)
    {
      response = new Response();
      response.headers['Content-Type'] = "text/htmll";
      if (parseInt(errCode,10))
      {
	response.code = errCode;
	response.content = "";
      }
      else
      {
	response.code = 500;
	response.content = errCode.toString();
	debug("ERR:" + errCode);
      }
    }
    this._sendResponse(response, client);
    client.disconnectFromHost();
  }
  catch (ex)
  {
    alert("Boolbool Error:" + ex);
  }
};
HTTPServer.prototype._sendResponse = function(response, client)
{
  isIoDevice = ((response.content.inherits !== undefined) && (response.content.inherits('QIODevice')));
  if (isIoDevice)
  {
    d = response.content;
    l = d.size();
  }
  else
  {
    d = new QByteArray(response.content);
    l = d.length();
  }
  client.write(new QByteArray('HTTP/1.1 ' + response.code + " " + eStatusCode[response.code] + '\r\n'));
  for (header in response.headers)
  {
    client.write(new QByteArray(header + ":" + response.headers[header] + "\r\n"));
  }
  client.write(new QByteArray('Content-Length: ' + l + '\r\n'));
  client.write(new QByteArray('Server: ' + this.serverName + " " + this.serverVersion + '\r\n'));
  client.write(new QByteArray('\r\n'));
  client.waitForBytesWritten(-1);
  if (!isIoDevice)
  {
    client.write(d);
  }
  else
  {
    for(;;)
    {
      data = response.content.read(10*KB);
      
      if (data.length() === 0)
      {
	break;
      }
      client.write(data);
    }
  }
  client.waitForBytesWritten(-1);
  //debug('finished');
};

HTTPServer.prototype._parseRequest = function(ioDevice)
{
  reSplit = "^([^\\s:]*)\\s*:\\s*(.*)$";
  request = {};
  var line = ioDevice.readLine(0).toString();
  line = line.replace('\r\n', '');
  tmp = line.split(' ');
  request.method = tmp[0];
  request.path = new QUrl(tmp[1]);
  request.serverVersion = tmp[2];
  request.headers = {};
  
  for (;;)
  {
    line = ioDevice.readLine(0).toString();
    line = line.replace('\r\n', '');
    
    if (line === "")
    {
      break;
    }
  
    tmp = line.match(reSplit);
    request.headers[tmp[1]] = tmp[2];
  }
  if (request.headers.hasOwnProperty('Content-Length'))
  {
    request.body = ioDevice.read(parseInt(request.headers['Content-Length'], 10)).toString();
  }
  else
  {
    request.body = "";
  }
  return request;
};